﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Data.Objects;
using System.Linq;
using System.Text;
using AutoPoco.Engine;

namespace DataGeneration.Makers
{
    abstract class Maker<T> : IMaker where T : class
    {
        private QuizzMeEntities _entities;
        public ObjectSet<T> ObjectSet
        {
            get
            {
                return (ObjectSet<T>) typeof (QuizzMeEntities).GetProperties().FirstOrDefault(
                    p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericArguments().Contains(typeof(T))).GetValue(_entities, null);
            }
        }

        private IGenerationSession _session;

        [Import]
        public IGenerationSession Session
        {
            get { return _session; }
            set { _session = value; }
        }

        [Import]
        public QuizzMeEntities Entities
        {
            get { return _entities; }
            set { _entities = value; }
        }

        protected abstract IEnumerable<T> GetList();

        public void Apply()
        {
            Logger.LogLow("%cyan%  [Building {0} objects]", typeof(T).Name);
            try
            {
                Make(ObjectSet, GetList());
            }
            catch (Exception e)
            {
                Logger.LogLow("%red%[EXCEPTION] {0}", e.Message);
            }
        }

        public void Delete()
        {
            Logger.LogLow("%red%Deleting {0} table...", typeof(T).Name);
            try
            {
                foreach (var d in ObjectSet)
                    ObjectSet.DeleteObject(d);
            }
            catch (Exception e)
            {
                Logger.LogLow("%red%[EXCEPTION] {0}", e.Message);
            }
        }

        private static void Make(ObjectSet<T> objectSet, IEnumerable<T> list)
        {
            if(list == null)
                return;
            Logger.LogLow("%cyan%  [Making {0}]", typeof(T).Name);
            Logger.LogLow("    Adding {0} objects...", list.Count());
            foreach (var difficulty in list)
            {
                Logger.LogHigh(Display(difficulty, false));
                objectSet.AddObject(difficulty);
            }
            Logger.LogLow("      done.");
        }

        private static string Display(object obj, bool inline = true)
        {
            var sb = new StringBuilder();
            Type t = obj.GetType();

            Logger.LogHigh("%blue%[{0}]", obj.GetType().Name);
            if (t.IsPrimitive || obj is string)
                sb.AppendInline(inline, obj.ToString());
            else
                sb = t.GetProperties().Aggregate(sb, (current, info) => current.AppendInline(inline, "{0} => {1}", info.Name, info.GetValue(obj, null)));
            return sb.ToString();
        }
    }
}
